{
  This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
  the Free Software Foundation; version 2 of the License.
   
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
}

// Copyright (c) 2010 2011 2012 - J. Aldo G. de Freitas Junior

{$mode objfpc}
{$H+}

Unit
	ExprParser;
	
Interface

Uses
	Classes,
	SysUtils,
	BaseException,
	ExprScanner,
	ExprNodes;

Type
	TExprParser = Class
	Private
		fSource : TExprTokenIterator;
		fDestination : TExprNode;
		fClassFactory : TCommandFactory;
	Public
		Property Source : TExprTokenIterator Read fSource;
		Constructor Create(Const aSource : TExprTokenIterator; Const aDestination : TExprNode; Const aClassFactory : TCommandFactory);
		Procedure Mark(Const aNode : TExprNode);
		// Simple expressions
		Function ParseUnaryMinus(Const aPrevious : TExprNode): TExprNode;
		Function ParseUnaryNot(Const aPrevious : TExprNode): TExprNode;
		Function ParseFunctionCall(Const aPrevious : TExprNode): TExprNode;
		Function ParseStringLiteral(Const aPrevious : TExprNode): TExprNode;
		Function ParseNumberLiteral(Const aPrevious : TExprNode): TExprNode;
		Function ParseFloatLiteral(Const aPrevious : TExprNode): TExprNode;
		Function ParseLiteral(Const aPrevious : TExprNode): TExprNode;
		Function ParseTerm(Const aPrevious : TExprNode): TExprNode;
		Function ParseMulExpression(Const aPrevious : TExprNode): TExprNode;
		Function ParseAddExpression(Const aPrevious : TExprNode): TExprNode;
		Function ParseExpression(Const aPrevious : TExprNode): TExprNode;
		Function ParseExpressionList(Const aPrevious : TExprNode): TExprNode;
		Function ParseParameters: TExprNode;
		Function ParseSingleExpression: TExprNode;
		// Domain names
		Function ParseProperty(Const aPrevious : TExprNode): TExprNode;
		Function ParsePropertyList(Const aPrevious : TExprNode): TExprNode;
		Function ParseNodeName(Const aPrevious : TExprNode): TExprNode;
		Function ParseIntrinsic(Const aPrevious : TExprNode): TExprNode;
		Function ParseNumericNodeReference(Const aPrevious : TExprNode): TExprNode;
		Function ParseExpressionNodeReference(Const aPrevious : TExprNode): TExprNode;
		Function ParseNodeReference(Const aPrevious : TExprNode): TExprNode;
		Function ParseDomainName(Const aPrevious : TExprNode): TExprNode;
		// Commands
		Function ParseFocusCommand(Const aPrevious : TExprNode): TExprNode;
		Function ParseCommandWithoutParameters(Const aPrevious : TExprNode): TExprNode;
		Function ParseCommandWithDomainName(Const aPrevious : TExprNode): TExprNode;
		Function ParseCommandWithProperties(Const aPrevious : TExprNode): TExprNode;
		Function ParseCommandWithClassNameAndProperties(Const aPrevious : TExprNode): TExprNode;
		Function ParseCommandWithIdentifier(Const aPrevious : TExprNode): TExprNode;
		Function ParseCommandWithExpression(Const aPrevious : TExprNode): TExprNode;
		Function ParseCommandWithExpressionList(Const aPrevious : TExprNode): TExprNode;
		Function ParseCommand(Const aPrevious : TExprNode): TExprNode;
		Function ParseCommandBlock(Const aPrevious : TExprNode): TExprNode;
		Function ParseWhile(Const aPrevious : TExprNode): TExprNode;
		Function ParseIf(Const aPrevious : TExprNode): TExprNode;
		Function ParseFor(Const aPrevious : TExprNode): TExprNode;
		Function ParseBreak(Const aPrevious : TExprNode): TExprNode;
		Function ParseAssign(Const aPrevious : TExprNode): TExprNode;
		Function ParseInputCommand: TExprNode;
		Function ParseDomainNameExpression: TExprNode;
	End;

Implementation

Constructor TExprParser.Create(Const aSource : TExprTokenIterator; Const aDestination : TExprNode; Const aClassFactory : TCommandFactory);
Begin
	Inherited Create;
	fSource := aSource;
	fDestination := aDestination;
	fClassFactory := aClassFactory;
End;

Procedure TExprParser.Mark(Const aNode : TExprNode);
Begin
	aNode.Row := fSource.Row;
	aNode.Col := fSource.Col;
	aNode.Source := fSource.SourceName;
End;

Function TExprParser.ParseUnaryMinus(Const aPrevious : TExprNode): TExprNode;
Var
	lUnaryMinus : TUnaryMinusNode;
Begin
	// Debug WriteLn('ParseUnaryMinus');
	lUnaryMinus := TUnaryMinusNode.Create(aPrevious);
	Mark(lUnaryMinus);
	fSource.Consume('-');
	ParseTerm(lUnaryMinus);
	Result := lUnaryMinus;
End;

Function TExprParser.ParseUnaryNot(Const aPrevious : TExprNode): TExprNode;
Var
	lUnaryNot : TUnaryNotNode;
Begin
	// Debug WriteLn('ParseUnaryNot');
	lUnaryNot := TUnaryNotNode.Create(aPrevious);
	Mark(lUnaryNot);
	fSource.Consume('not');
	ParseTerm(lUnaryNot);
	Result := lUnaryNot;
End;

Function TExprParser.ParseFunctionCall(Const aPrevious : TExprNode): TExprNode;
Var
	lFunctionCall : TFunctionCallNode;
Begin
	// Debug WriteLn('ParseFunctionCall');
	lFunctionCall := TFunctionCallNode.Create(aPrevious);
	Mark(lFunctionCall);
	lFunctionCall.Name := fSource.Extract(tkExprIdentifier);
	If fSource.Consume('(', False) Then
	Begin
		If Not(fSource.Expected(')')) Then
			lFunctionCall.Parameters := ParseExpressionList(lFunctionCall) As TExpressionListNode;
		fSource.Consume(')');
	End
	Else
		lFunctionCall.Parameters := Nil;
	Result := lFunctionCall;
End;

Function TExprParser.ParseStringLiteral(Const aPrevious : TExprNode): TExprNode;
Var
	lStringLiteral : TStringLiteralNode;
Begin
	// Debug WriteLn('ParseStringLiteral');
	lStringLiteral := TStringLiteralNode.Create(aPrevious);
	Mark(lStringLiteral);
	lStringLiteral.Value := fSource.Extract(tkExprLiteralString);
	// Debug WriteLn(lStringLiteral.Value);
	Result := lStringLiteral;
End;

Function TExprParser.ParseNumberLiteral(Const aPrevious : TExprNode): TExprNode;
Var
	lNumberLiteral : TNumberLiteralNode;
Begin
	// Debug WriteLn('ParseNumberLiteral');
	lNumberLiteral := TNumberLiteralNode.Create(aPrevious);
	lNumberLiteral.IsFloat := False;
	Mark(lNumberLiteral);
	lNumberLiteral.Value := fSource.Extract(tkExprLiteralNumber);
	// Debug WriteLn(lNumberLiteral.Value);
	Result := lNumberLiteral;
End;

Function TExprParser.ParseFloatLiteral(Const aPrevious : TExprNode): TExprNode;
Var
	lNumberLiteral : TNumberLiteralNode;
Begin
	// Debug WriteLn('ParseNumberLiteral');
	lNumberLiteral := TNumberLiteralNode.Create(aPrevious);
	lNumberLiteral.IsFloat := True;
	Mark(lNumberLiteral);
	lNumberLiteral.Value := fSource.Extract(tkExprLiteralNumber);
	// Debug WriteLn(lNumberLiteral.Value);
	Result := lNumberLiteral;
End;

Function TExprParser.ParseLiteral(Const aPrevious : TExprNode): TExprNode;
Begin
	// Debug WriteLn('ParseLiteral');
	If fSource.Expected(tkExprLiteralString) Then
		Result := ParseStringLiteral(aPrevious)
	Else If fSource.Expected(tkExprLiteralNumber) Then
		Result := ParseNumberLiteral(aPrevious)
	Else
		fSource.RaiseError('Expected string or number, got "' + fSource.Literal + '"');
End;

Function TExprParser.ParseTerm(Const aPrevious : TExprNode): TExprNode;
Begin
	// Debug WriteLn('ParseTerm');
	If fSource.Expected('-') Then
		Result := ParseUnaryMinus(aPrevious)
	Else If fSource.Expected('not') Then
		Result := ParseUnaryNot(aPrevious)
	Else If fSource.Expected(tkExprIdentifier) Then
		Result := ParseFunctionCall(aPrevious)
	Else If fSource.Expected('(') Then
	Begin
		fSource.Consume('(');
		Result := ParseExpression(aPrevious);
		fSource.Consume(')');
	End
	Else
		Result := ParseLiteral(aPrevious);
End;

Function TExprParser.ParseMulExpression(Const aPrevious : TExprNode): TExprNode;
Var
	lMul : TMulExpressionNode;
Begin
	// Debug WriteLn('ParseMulExpression');
	lMul := TMulExpressionNode.Create(aPrevious);
	lMul.Operation := '';
	ParseTerm(lMul);
	If fSource.Expected(['*', '/', 'div', 'mod', 'and', '^']) Then
	Begin
		Mark(lMul);
		lMul.Operation := fSource.Extract(tkExprWord);
		ParseMulExpression(lMul);
	End;
	Result := lMul;
End;

Function TExprParser.ParseAddExpression(Const aPrevious : TExprNode): TExprNode;
Var
	lAdd : TAddExpressionNode;
Begin
	// Debug WriteLn('ParseAddExpression');
	lAdd := TAddExpressionNode.Create(aPrevious);
	lAdd.Operation := '';
	ParseMulExpression(lAdd);
	If fSource.Expected(['+', '-', 'or', 'xor']) Then
	Begin
		Mark(lAdd);
		lAdd.Operation := fSource.Extract(tkExprWord);
		ParseAddExpression(lAdd);
	End;
	Result := lAdd;
End;

Function TExprParser.ParseExpression(Const aPrevious : TExprNode): TExprNode;
Var
	lCompare : TExpressionNode;
Begin
	// Debug WriteLn('ParseExpression');
	lCompare := TExpressionNode.Create(aPrevious);
	lCompare.Operation := '';
	ParseAddExpression(lCompare);
	If fSource.Expected(['=', '<', '>', '<=', '>=', '<>']) Then
	Begin
		Mark(lCompare);
		lCompare.Operation := fSource.Extract(tkExprWord);
		ParseAddExpression(lCompare);
	End;
	Result := lCompare;
End;

Function TExprParser.ParseExpressionList(Const aPrevious : TExprNode): TExprNode;
Var
	lExpressionList : TExpressionListNode;
Begin
	// Debug WriteLn('ParseExpressionList');
	lExpressionList := TExpressionListNode.Create(aPrevious);
	Mark(lExpressionList);
	Repeat
		ParseExpression(lExpressionList);	
	Until Not(fSource.Consume(',', False));
	Result := lExpressionList;
End;

Function TExprParser.ParseParameters: TExprNode;
Begin
	// Debug WriteLn('ParseSource');
	Repeat
		ParseExpression(fDestination);
	Until Not(fSource.Consume(',', False));
	fSource.Consume(tkExprEOF);
	Result := fDestination;
End;

Function TExprParser.ParseSingleExpression: TExprNode;
Begin
	// Debug WriteLn('ParseSource');
	ParseExpression(fDestination);
	fSource.Consume(tkExprEOF);
	Result := fDestination;
End;

Function TExprParser.ParseProperty(Const aPrevious : TExprNode): TExprNode;
Var
	lProperty : TPropertyNode;
Begin
	// Debug  WriteLn('ParseProperty');
	lProperty := TPropertyNode.Create(aPrevious);
	Mark(lProperty);
	lProperty.Name := Source.Extract(tkExprIdentifier);
	Source.Consume('=');
	lProperty.Value := ParseExpression(lProperty) As TExpressionNode;
	Result := lProperty;
End;

Function TExprParser.ParsePropertyList(Const aPrevious : TExprNode): TExprNode;
Var
	lPropertyList : TPropertyListNode;
Begin
	// Debug  WriteLn('ParsePropertyList');
	lPropertyList := TPropertyListNode.Create(aPrevious);
	Mark(lPropertyList);
	If Source.Expected(tkExprIdentifier, False) Then
		While Source.Expected(tkExprIdentifier, False) Do
			ParseProperty(lPropertyList);
	Result := lPropertyList;
End;

Function TExprParser.ParseNodeName(Const aPrevious : TExprNode): TExprNode;
Var
	lNodeName : TNodeNameNode;
Begin
	// Debug  WriteLn('ParseNodeName');	
	lNodeName := TNodeNameNode.Create(aPrevious);
	Mark(lNodeName);
	lNodeName.Name := Source.Extract(tkExprIdentifier);
	Result := lNodeName;
End;

Function TExprParser.ParseIntrinsic(Const aPrevious : TExprNode): TExprNode;
Var
	lIntrinsicNode : TIntrinsicNode;
Begin
	// Debug  WriteLn('ParseIntrinsic');	
	lIntrinsicNode := TIntrinsicNode.Create(aPrevious);
	Mark(lIntrinsicNode);
	Source.Consume('$');
	lIntrinsicNode.Name := Source.Extract(tkExprIdentifier);
	Source.Consume('$');
	Result := lIntrinsicNode;
End;

Function TExprParser.ParseNumericNodeReference(Const aPrevious : TExprNode): TExprNode;
Var
	lNumericReference : TNumericReferenceNode;
Begin
	// Debug  WriteLn('ParseNumericNodeReference');	
	lNumericReference := TNumericReferenceNode.Create(aPrevious);
	Mark(lNumericReference);
	Source.Consume('[');
	lNumericReference.Expression := ParseExpression(lNumericReference) As TExpressionNode;
	Source.Consume(']');
	Result := lNumericReference;
End;

Function TExprParser.ParseExpressionNodeReference(Const aPrevious : TExprNode): TExprNode;
Var
	lExpressionReference : TExpressionReferenceNode;
Begin
	// Debug  WriteLn('ParseExpressionNodeReference');
	lExpressionReference := TExpressionReferenceNode.Create(aPrevious);
	Mark(lExpressionReference);
	Source.Consume('|');
	lExpressionReference.Properties := ParsePropertyList(lExpressionReference) As TPropertyListNode;
	Source.Consume('|');
	Result := lExpressionReference;
End;

Function TExprParser.ParseNodeReference(Const aPrevious : TExprNode): TExprNode;
Begin
	// Debug  WriteLn('ParseNodeReference');
	If Source.Expected('$') Then
		Result := ParseIntrinsic(aPrevious)
	Else If Source.Expected('[') Then
		Result := ParseNumericNodeReference(aPrevious)
	Else If Source.Expected('|') Then
		Result := ParseExpressionNodeReference(aPrevious)
	Else
		Result := ParseNodeName(aPrevious);
End;

Function TExprParser.ParseDomainName(Const aPrevious : TExprNode): TExprNode;
Var
	lDomainName : TDomainNameNode;
Begin
	// Debug  WriteLn('ParseDomainName');
	lDomainName := TDomainNameNode.Create(aPrevious);
	Mark(lDomainName);
	Repeat
		ParseNodeReference(lDomainName);
	Until Not Source.Consume('.', False);
	Result := lDomainName;
End;

Function TExprParser.ParseFocusCommand(Const aPrevious : TExprNode): TExprNode;
Var
	lFocusCommand : TFocusCommand;
Begin
	// Debug  WriteLn('ParseFocusCommand');
	lFocusCommand := TFocusCommand.Create(aPrevious);
	Mark(lFocusCommand);
	Source.Consume('/');
	lFocusCommand.DomainName := ParseDomainName(lFocusCommand) As TDomainNameNode;
	If Not Source.Expected(tkExprEOF, False) Or Source.Expected(tkExprLineBreak) Then
		lFocusCommand.Command := ParseCommand(lFocusCommand) As TExprNode
	Else
		lFocusCommand.Command := Nil;
	Result := lFocusCommand;
End;

Function TExprParser.ParseCommandWithoutParameters(Const aPrevious : TExprNode): TExprNode;
Var
	lRow,
	lColumn : Integer;
	lSource : String;
Begin
	// Debug  WriteLn('ParseCommandWithoutParameters');
	// Debug  WriteLn('Command : ', Source.Literal);
	lRow := Source.Row;
	lColumn := Source.Col;
	lSource := Source.SourceName;
	Result := fClassFactory.Build(Source.Extract(tkExprIdentifier), aPrevious) As TExprNode;
	Result.Row := lRow;
	Result.Col := lColumn;
	Result.Source := lSource;
End;

Function TExprParser.ParseCommandWithDomainName(Const aPrevious : TExprNode): TExprNode;
Var
	lRow,
	lColumn : Integer;
	lSource : String;
Begin
	// Debug  WriteLn('ParseCommandWithDomainName');
	// Debug  WriteLn('Command : ', Source.Literal);
	lRow := Source.Row;
	lColumn := Source.Col;
	lSource := Source.SourceName;
	Result := fClassFactory.Build(Source.Extract(tkExprIdentifier), aPrevious) As TExprNode;
	(Result As TCommandWithDomainName).DomainName := ParseDomainName(Result) As TDomainNameNode;
	Result.Row := lRow;
	Result.Col := lColumn;
	Result.Source := lSource;
End;

Function TExprParser.ParseCommandWithProperties(Const aPrevious : TExprNode): TExprNode;
Var
	lRow,
	lColumn : Integer;
	lSource : String;
Begin
	// Debug  WriteLn('ParseCommandWithProperties');
	// Debug  WriteLn('Command : ', Source.Literal);
	lRow := Source.Row;
	lColumn := Source.Col;
	lSource := Source.SourceName;
	Result := fClassFactory.Build(Source.Extract(tkExprIdentifier), aPrevious) As TExprNode;
	If Source.Expected(tkExprIdentifier, False) Then
		(Result As TCommandWithProperties).Properties := ParsePropertyList(Result) As TPropertyListNode
	Else
		(Result As TCommandWithProperties).Properties := Nil;
	Result.Row := lRow;
	Result.Col := lColumn;
	Result.Source := lSource;
End;

Function TExprParser.ParseCommandWithClassNameAndProperties(Const aPrevious : TExprNode): TExprNode;
Var
	lRow,
	lColumn : Integer;
	lSource : String;
Begin
	// Debug  WriteLn('ParseCommandWithClassNameAndProperties');
	// Debug  WriteLn('Command : ', Source.Literal);
	lRow := Source.Row;
	lColumn := Source.Col;
	lSource := Source.SourceName;
	Result := fClassFactory.Build(Source.Extract(tkExprIdentifier), aPrevious) As TExprNode;
	(Result As TCommandWithClassNameAndProperties).NameOfClass := Source.Extract(tkExprIdentifier);
	If Source.Expected(tkExprIdentifier, False) Then
		(Result As TCommandWithClassNameAndProperties).Properties := ParsePropertyList(Result) As TPropertyListNode
	Else
		(Result As TCommandWithClassNameAndProperties).Properties := Nil;
	Result.Row := lRow;
	Result.Col := lColumn;
	Result.Source := lSource;
End;

Function TExprParser.ParseCommandWithIdentifier(Const aPrevious : TExprNode): TExprNode;
Var
	lRow,
	lColumn : Integer;
	lSource : String;
Begin
	// Debug  WriteLn('ParseCommandWithIdentifier');
	// Debug  WriteLn('Command : ', Source.Literal);
	lRow := Source.Row;
	lColumn := Source.Col;
	lSource := Source.SourceName;
	Result := fClassFactory.Build(Source.Extract(tkExprIdentifier), aPrevious) As TExprNode;
	(Result As TCommandWithIdentifier).PropertyName := Source.Extract(tkExprIdentifier);
	Result.Row := lRow;
	Result.Col := lColumn;
	Result.Source := lSource;
End;

Function TExprParser.ParseCommandWithExpression(Const aPrevious : TExprNode): TExprNode;
Var
	lRow,
	lColumn : Integer;
	lSource : String;
Begin
	// Debug  WriteLn('ParseCommandWithExpression');
	// Debug  WriteLn('Command : ', Source.Literal);
	lRow := Source.Row;
	lColumn := Source.Col;
	lSource := Source.SourceName;
	Result := fClassFactory.Build(Source.Extract(tkExprIdentifier), aPrevious) As TExprNode;
	(Result As TCommandWithExpression).Expression := ParseExpression(Result) As TExpressionNode;
	Result.Row := lRow;
	Result.Col := lColumn;
	Result.Source := lSource;
End;

Function TExprParser.ParseCommandWithExpressionList(Const aPrevious : TExprNode): TExprNode;
Var
	lRow,
	lColumn : Integer;
	lSource : String;
Begin
	// Debug  WriteLn('ParseCommandWithExpressionList');
	// Debug  WriteLn('Command : ', Source.Literal);
	lRow := Source.Row;
	lColumn := Source.Col;
	lSource := Source.SourceName;
	Result := fClassFactory.Build(Source.Extract(tkExprIdentifier), aPrevious) As TExprNode;
	If Not 
		((Source.Expected(tkExprLineBreak, False) Or Source.Expected(tkExprEOF, False)) Or
		Source.Expected(';', False)) Then
		(Result As TCommandWithExpressionList).ExpressionList := ParseExpressionList(Result) As TExpressionListNode
	Else
		(Result As TCommandWithExpressionList).ExpressionList := Nil;
	Result.Row := lRow;
	Result.Col := lColumn;
	Result.Source := lSource;
End;

Function TExprParser.ParseCommand(Const aPrevious : TExprNode): TExprNode;
Var
	lKind : TCommandKind;
Begin
	// Debug  WriteLn(Source.Literal);
	If Source.Literal = ';' Then
	Begin
		Result := Nil;
		Source.Consume(';');
	End
	Else If Source.Expected(tkExprLineBreak, False) Then
		Source.Consume(tkExprLineBreak)
	Else If Source.IsAssign Then
		Result := ParseAssign(aPrevious)
	Else If Source.Literal = 'else' Then
		Result := Nil
	Else If Source.Literal = '/' Then
		Result := ParseFocusCommand(aPrevious)
	Else If Source.Literal = '{' Then
		Result := ParseCommandBlock(aPrevious)
	Else If LowerCase(Source.Literal) = 'while' Then
		Result := ParseWhile(aPrevious)
	Else If LowerCase(Source.Literal) = 'if' Then
		Result := ParseIf(aPrevious)
	Else If LowerCase(Source.Literal) = 'for' Then
		Result := ParseFor(aPrevious)
	Else If LowerCase(Source.Literal) = 'break' Then
		Result := ParseBreak(aPrevious)
	Else
	Begin
		// Debug  WriteLn('ParseCommand');
		lKind := fClassFactory.CommandKind(Source.Literal);
		// Debug  WriteLn(Source.Literal, '=', lKind);
		If lKind = ckCommandWithoutParameters Then
			Result := ParseCommandWithoutParameters(aPrevious)
		Else If lKind = ckCommandWithDomainName Then
			Result := ParseCommandWithDomainName(aPrevious)
		Else If lKind = ckCommandWithProperties Then
			Result := ParseCommandWithProperties(aPrevious) 
		Else If lKind = ckCommandWithClassNameAndProperties Then
			Result := ParseCommandWithClassNameAndProperties(aPrevious)
		Else If lKind = ckCommandWithIdentifier Then
			Result := ParseCommandWithIdentifier(aPrevious)
		Else If lKind = ckCommandWithExpression Then
			Result := ParseCommandWithExpression(aPrevious)
		Else If lKind = ckCommandWithExpressionList Then
			Result := ParseCommandWithExpressionList(aPrevious)
		Else
		Begin
			Result := Nil;
			Source.RaiseError('Unknown command, "' + Source.Literal + '".');
		End;
	End;
End;

Function TExprParser.ParseCommandBlock(Const aPrevious : TExprNode): TExprNode;
Var
	lCommandBlock : TCommandBlock;
Begin
	// Debug  WriteLn('ParseCommandBlock');
	lCommandBlock := TCommandBlock.Create(aPrevious);
	Mark(lCommandBlock);
	Source.Consume('{');
	Repeat
		While fSource.Consume(';', False) Do ;
		While fSource.Consume(tkExprLineBreak, False) Do ;
		If Not fSource.Expected('}', False) Then
			ParseCommand(lCommandBlock);
	Until Source.ConsumeElse('}', ';');
	Result := lCommandBlock As TExprNode;
End;

Function TExprParser.ParseWhile(Const aPrevious : TExprNode): TExprNode;
Var
	lWhileCommand : TWhileCommand;
Begin
	lWhileCommand := TWhileCommand.Create(aPrevious);
	Mark(lWhileCommand);
	Source.Consume('while');
	lWhileCommand.Condition := ParseExpression(lWhileCommand) As TExpressionNode;
	Source.Consume('do');
	lWhileCommand.Command := ParseCommand(lWhileCommand) As TExprNode;
	Result := lWhileCommand As TExprNode;
End;

Function TExprParser.ParseIf(Const aPrevious : TExprNode): TExprNode;
Var
	lIfCommand : TIfCommand;
Begin
	lIfCommand := TIfCommand.Create(aPrevious);
	Mark(lIfCommand);
	Source.Consume('if');
	lIfCommand.Condition := ParseExpression(lIfCommand) As TExpressionNode;
	Source.Consume('then');
	lIfCommand.ThenCommand := ParseCommand(lIfCommand) As TExprNode;
	If Source.Consume('else', False) Then
		lIfCommand.ElseCommand := ParseCommand(lIfCommand) As TExprNode
	Else
		lIfCommand.ElseCommand := Nil;
	Result := lIfCommand As TExprNode;
End;

Function TExprParser.ParseFor(Const aPrevious : TExprNodE): TExprNode;
Var
	lForCommand : TForCommand;
Begin
	lForCommand := TForCommand.Create(aPrevious);
	Mark(lForCommand);
	Source.Consume('for');
	Source.Consume('each');
	lForCommand.Node := ParseDomainName(lForCommand) As TDomainNameNode;
	Source.Consume('do');
	lForCommand.Command := ParseCommand(lForCommand) As TExprNode;
	Result := lForCommand As TExprNode;
End;

Function TExprParser.ParseBreak(Const aPrevious : TExprNodE): TExprNode;
Var
	lBreakCommand : TBreakCommand;
Begin
	lBreakCommand := TBreakCommand.Create(aPrevious);
	Mark(lBreakCommand);
	Source.Consume('break');
	Result := lBreakCommand As TExprNode;
End;

Function TExprParser.ParseAssign(Const aPrevious : TExprNode): TExprNode;
Var
	lAssign : TVarAssignmentCommand;
Begin
	lAssign := TVarAssignmentCommand.Create(aPrevious);
	Mark(lAssign);
	lAssign.Name := Source.Extract(tkExprIdentifier);
	Source.Consume('=');
	lAssign.Value := ParseExpression(lAssign) As TExpressionNode;
	Result := lAssign;
End;

Function TExprParser.ParseInputCommand: TExprNode;
Begin
	// Debug  WriteLn('ParseInputCommand');
	Result := ParseCommand(fDestination);
	While fSource.Consume(';', False) Do ;
	While fSource.Consume(tkExprLineBreak, False) Do ;
	Source.Consume(tkExprEOF);
End;

Function TExprParser.ParseDomainNameExpression: TExprNode;
Begin
	Result := ParseDomainName(fDestination);
End;

End.
